# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
 -------------------------------------------------
    File Name:     executor.py
    Description:   执行引擎架构
 -------------------------------------------------
 """
from datetime import datetime
import threading
from queue import Queue
import requests
from abc import ABC, abstractmethod
from core.result_model import TestCaseResult, TestSuiteResult
from core.basecase import BaseCase


class ITestExecutor(ABC):
    """测试执行器抽象类"""

    @abstractmethod
    def execute_test(self, test_func, case_data: dict) -> TestCaseResult:
        """执行单个测试函数"""
        pass


class SyncTestExecutor(ITestExecutor):
    """同步执行器 (基础实现)"""

    def __init__(self, client=None):
        self.client = client or requests.Session()

    def execute_test(self, test_func: None, case_data: dict) -> TestCaseResult:
        result = TestCaseResult()  # 创建测试结果对象
        result.start_time = datetime.now()  # 记录开始时间

        try:
            # response = self.client.request(
            #     method=case_data["method"],
            #     url=case_data["url"],
            #     headers=case_data.get("headers"),
            #     params=case_data.get("params"),
            #     json=case_data.get("body"),
            #     timeout=10
            # )

            response = BaseCase().perform(case_data)

            result.status_code = response.status_code

            # 自动断言示例
            if result.status_code >= 400:
                raise Exception(f"Request failed with status {result.status_code}")

            result.finish("Passed")
        except Exception as e:
            result.error_trace = str(e)
            result.finish("Failed")
        finally:
            result.end_time = datetime.now()  # 记录结束时间

        return result


# === 异步测试执行器（待实现） ===
class AsyncTestExecutor(ITestExecutor):
    """异步执行器（适用于高并发场景）"""

    async def execute_test_async(self, test_func, case_data: dict) -> TestCaseResult:
        """异步执行测试函数的实现（需补充）"""
        # 使用aiohttp实现异步请求的示例框架：
        # async with aiohttp.ClientSession() as session:
        #     async with session.post(...) as response:
        #         ...
        pass


# === 测试调度中心 ===
class ExecutionScheduler:
    """测试调度中心，管理测试用例执行"""

    def __init__(self, executor: ITestExecutor, name="Default Suite"):
        self.executor = executor  # 绑定的测试执行器
        self.test_queue = Queue()  # 测试用例队列
        # self.results = []  # 存储所有测试结果
        self.suite_result = TestSuiteResult(name=name)
        self.worker_threads = []  # 工作线程列表

    def add_test_cases(self, cases: list) -> None:
        """
        添加测试用例到调度器

        :param cases: 测试用例列表（每个元素应为包含"id"和"params"的字典）
        """
        # 遍历测试用例列表
        for case in cases:
            # 将测试用例添加到队列
            self.test_queue.put(case)

    def run_concurrently(self, max_workers: int = 5) -> None:
        """
        并发执行测试用例

        :param max_workers: 最大并发线程数
        """
        # 创建工作线程
        for _ in range(max_workers):
            # 创建线程并启动
            t = threading.Thread(target=self._worker)  # 传入_worker方法作为目标
            t.start()
            # 将线程添加到列表
            self.worker_threads.append(t)

        # 等待所有线程完成
        for t in self.worker_threads:
            t.join()  # 等待线程结束

    def _worker(self) -> None:
        """
        工作线程方法，从队列中取出测试用例并执行
        """
        while not self.test_queue.empty():  # 当队列不为空时
            case_data = self.test_queue.get()  # 从队列中取出一个测试用例数据

            # 注意：此处存在闭包问题！建议改为：
            # result = self.executor.execute_test(test_func, case_data)

            # 原代码的问题在于lambda会延迟绑定，可能导致所有线程使用最后一个case_data
            # 正确用法应该直接传递当前case_data：

            result = self.executor.execute_test(  # 单个用例（接口）的执行
                # test_func=lambda x, c=case_data: self._run_case(c, x),
                test_func=None,
                case_data=case_data
            )
            # self.results.append(result)  # 将结果添加到结果列表
            self.suite_result.add_case(result)  # 将结果添加到套件统计

    @staticmethod
    def _run_case(case_data, test_func) -> dict:
        """
        测试函数前置处理（模拟环境准备）

        :param case_data: 测试用例数据
        :param test_func: 实际测试函数
        :return: 模拟响应数据
        """
        print(f"Executing case {case_data['id']}...")
        # 在实际项目中，这里应调用test_func并返回响应数据
        return {
            "status_code": 200,
            "name": "调试运行"
        }


def main(case_set):
    # 示例用法

    # 2. 创建同步执行器
    sync_executor = SyncTestExecutor()

    # for cases in case_set:
    # 3. 创建调度器并绑定执行器(自行指定)
    scheduler = ExecutionScheduler(executor=sync_executor, name=case_set["name"])

    # 4. 添加测试用例（添加到调度器）
    scheduler.add_test_cases(case_set["cases"])  # 传入测试场景

    # 5. 并发执行测试
    scheduler.run_concurrently(max_workers=1)

    # 6. 输出结果
    # 输出测试套件结果
    print(f"========================== {scheduler.suite_result.name} ==========================")
    # print(f"套件名称: {scheduler.suite_result.name}")
    print(f"总用例数: {scheduler.suite_result.total}")
    print(f"通过数: {scheduler.suite_result.passed}")
    print(f"失败数: {scheduler.suite_result.failed}")
    print(f"耗时: {scheduler.suite_result.duration:.2f}s")

    # 打印详细用例结果
    for case_result in scheduler.suite_result.test_cases:
        print(f"------------------------------")
        print(f"Case ID: {case_result.case_id}")
        print(f"状态: {case_result.status}")
        print(f"耗时: {case_result.elapsed:.2f}s")
        if case_result.status == "Failed":
            print(f"错误跟踪: {case_result.error_trace}")


# === 使用示例 ===
if __name__ == "__main__":
    # test_cases = [
    #     {
    #         "id": "TC001",
    #         "params": {
    #             "base_url": "https://api.example.com",
    #             "method": "GET",
    #             "path": "/users/1"
    #         },
    #         "test_func": lambda: requests.get("https://api.example.com/users/1")
    #     },
    #     {
    #         "id": "TC002",
    #         "params": {
    #             "base_url": "https://api.example.com",
    #             "method": "POST",
    #             "path": "/users",
    #             "body": {"name": "test_user"}
    #         },
    #         "test_func": lambda: requests.post("https://api.example.com/users", json={"name": "test_user"})
    #     }
    # ]

    # 1. 准备测试用例
    case_set = {
        "name": "演示的用例集",
        "cases": test_cases
    }

    main(case_set=case_set)
